/*
 * fifo.c
 *
 *  Created on: 14/05/2010
 *      Author: chiche
 */

/*
 * fifo.c
 *
 *  Created on: May 10, 2010
 *      Author: apetit
 */

#include "../include/fifo.h"
#include "../include/kc.h"

static int fifo_counter = 0;
/*
 * si hay lugar en la tabla creo
 * creo un fifo_impl => offsets 0 y memoryZone = Malloc(fifosize * sizeof(char));
 * pongo el fifo en la tabla con un id autoincremental
 * y devuelvo ese id
 */
/**
 * Esto es la zona donde se escriben los fifos
 */
static char fifozone[100][500];

static int cmp_str2(char s1[], char s2[]) {
	int i;
	for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++) {
		if (s1[i] != s2[i]) {
			return -1;
		}
	}
	return 0;
}

void initializeFifos(void) {
	int i;
	for (i = 0; i < MAXFIFOSCANT; ++i) {
		((fifo_table[i]).fifo_id = -1);
	}
}

static int fifo_exists(char *name) {
	int i;

	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if ((cmp_str2(name, (fifo_table[i]).name) == 0
				&& (fifo_table[i]).fifo_id != -1)) {
			return 1;
		}
	}
	return 0;
}
/* si recive 0 imprime toda la tabla, con 1 impime solo los existentes*/
void printFifoTable(int option) {
	int i;
	char aux[4];
	if (option == 1) {
		print("Existent Fifo table information\n");
		for (i = 0; i < MAXFIFOSCANT; ++i) {
			if (fifo_table[i].fifo_id != -1) {
				print("Position: ");
				printd(i);
				print("\n  -Name: ");
				print(fifo_table[i].name);
				print("\n  -Id: ");
				printd(fifo_table[i].fifo_id);
				print("\n  -Start: ");
				printd(fifo_table[i].fifo.memoryZone);
				print("\n  -Lo que hay: ");
				print((char*) fifo_table[i].fifo.memoryZone);
				print("\n  -OffSetToRead: ");
				printd(fifo_table[i].fifo.offSetToRead);
				print("\n  -OffSetToWrite: ");
				printd(fifo_table[i].fifo.offSetToWrite);
				print("\n");
			}
		}
	} else if (option == 0) {
		print("All fifo table information\n");
		for (i = 0; i < MAXFIFOSCANT; ++i) {
			print("Position: ");
			printd(i);
			print("\n  -Name: ");
			print(fifo_table[i].name);
			print("\n  -Id: ");
			printd(aux);
			print("\n  -Start: ");
			print((char *) fifo_table[i].fifo.memoryZone);
			print("\n  -OffSetToRead: ");
			printd(fifo_table[i].fifo.offSetToRead);
			print("\n  -OffSetToWrite: ");
			printd(fifo_table[i].fifo.offSetToWrite);
			print("\n");
		}
	} else {
		print("Invalid option\n");
	}
}

int makeFifo(char * file_name) {
	int i;

	if (cmp_str2("..", file_name) == 0) {
		printf("\"..\" no es un nombre de archivo valido\n");
		return -1;
	}

	if (fifo_exists(file_name) == 1) {
		print("El fifo: ");
		print(file_name);
		print(" existe\n");
		return -1;
	}

	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if ((fifo_table[i]).fifo_id == -1) {
			break;
		}
	}
	(fifo_table[i]).fifo_id = fifo_counter++;
	strncpy((fifo_table[i]).name, file_name,strlen(file_name));
	//	((fifo_table[i]).fifo).memoryZone = (void *) Malloc(fifosize * sizeof(char));
	((fifo_table[i]).fifo).memoryZone = fifozone[i];
	((fifo_table[i]).fifo).offSetToRead = 0;
	(fifo_table[i]).fifo.offSetToWrite = 0;
	return (fifo_table[i]).fifo_id;

}

int openFifo(char * fifo_name) {
	int i;
	int resp = -1;
	//print("fifoname q mande->>>");
	//print(fifo_name);
	//print("<--\n");
	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if (cmp_str2(fifo_name, (fifo_table[i]).name) == 0
				&& fifo_table[i].fifo_id != -1) {
			resp = fifo_table[i].fifo_id;
			/*
			print("fifoname->");
			print((fifo_table[i]).name);
			print("<--\n");
			print("fifoid->");
			printd((fifo_table[i]).fifo_id);
			print("<--\n");
			*/
			break;
		}
	}
	/*
	print("resp->>>");
	printd(resp);
	print("<--\n");
	 */
	return resp;
}

/*
 * writeFifo
 * Hace un "memcpy"
 * de buff al fifo
 * algo as�
 * hacer la cuentita por si tiene que dar la vuelta (es decir que si oofsetToWrite > fifozise)
 * 	for(i = 0; i < nbytes; i++){
 * 		*(tablaDeFifos[where id=fd].fifo + offsetToWrite + i ) = buff[i];
 * 	}
 * 	offsetToWrite += i;
 * return bytesescritos o -1;
 *
 */

int writeFifo(int fd, void * buff, int nbytes) {
	int i;
	int read = -7, write = -7;
	void * base;
	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if ((fifo_table[i]).fifo_id == fd) {
			base = ((fifo_table[i]).fifo).memoryZone;
			read = ((fifo_table[i]).fifo).offSetToRead;
			write = ((fifo_table[i]).fifo).offSetToWrite;
			break;
		}
	}
	if (write == read && nbytes <= fifosize) {
		memcpy(buff, ((fifo_table[i]).fifo).memoryZone + write, nbytes);
		/*print("estoy en el fifo voy a leer la zona de memoria");
		 print((char*)((fifo_table[i]).fifo).memoryZone);
		 print("\n");*/
		if (write + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToWrite = 0;
		} else {
			((fifo_table[i]).fifo).offSetToWrite += nbytes;
		}
	} else if (write < read && write + nbytes > read) {
		print("Not enough space, write < read y write + nbytes > read\n");
		return -1;
	} else if (write > read && write + nbytes <= fifosize) {
		memcpy(buff, ((fifo_table[i]).fifo).memoryZone + write, nbytes);
		if (write + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToWrite = 0;
		} else {
			((fifo_table[i]).fifo).offSetToWrite += nbytes;
		}
	} else if (write > read && write + nbytes - fifosize > read) {
		print(
				"Not enough space, write > read y write + nbytes - fifosize > read\n");
		print("read ");
		printd(read);
		print(", write ");
		printd("write");
		print(", nbytes ");
		printd(nbytes);
		print(" ,fifosize ");
		printd(fifosize);
		print("\n");

		return -1;
	} else if (write > read && write + nbytes - fifosize < read) {
		memcpy(buff, ((fifo_table[i]).fifo).memoryZone + write, fifosize
				- write);
		memcpy(buff + fifosize - write, ((fifo_table[i]).fifo).memoryZone,
				write + nbytes - fifosize);
		((fifo_table[i]).fifo).offSetToWrite = write + nbytes - fifosize;
	} else if (write + nbytes < read) {
		memcpy(buff, ((fifo_table[i]).fifo).memoryZone + write, nbytes);
		if (write + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToWrite = 0;
		} else {
			((fifo_table[i]).fifo).offSetToWrite += nbytes;
		}
	}
	return nbytes;
}

/*
 * Read Fifo
 * analo al anterior pero en offsert to read
 * hay que valiadar si el proceso no entrega nada hasta que
 * offsetToRead <= offSetToWrite (hay q ver q esto sea atomico)
 * retorna bytes leidos o -1
 */

int readFifo(int fd, void * buff, int nbytes) {
	int i;
	int read, write;
	void * base;
	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if ((fifo_table[i]).fifo_id == fd) {
			base = ((fifo_table[i]).fifo).memoryZone;
			read = ((fifo_table[i]).fifo).offSetToRead;
			write = ((fifo_table[i]).fifo).offSetToWrite;
			break;
		}
	}

	if (write > read) {
		if (nbytes > write) {
			nbytes = write;
		}
	} else {
		if (fifosize - read + write < nbytes) {
			nbytes = fifosize - read + write;
		}
	}

	if (write == read) {
		//print("Nothing to read");
		return -1;
	} else if (read < write && read + nbytes <= write) {
		memcpy(((fifo_table[i]).fifo).memoryZone + read, buff, nbytes);
		if (read + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToRead = 0;
		} else {
			((fifo_table[i]).fifo).offSetToRead += nbytes;
		}
		return nbytes;
	} else if (read > write && read + nbytes <= fifosize) {
		memcpy(((fifo_table[i]).fifo).memoryZone + read, buff, nbytes);
		if (write + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToRead = 0;
		} else {
			((fifo_table[i]).fifo).offSetToRead += nbytes;
		}
	} else if (read > write && read + nbytes - fifosize > write) {
		//print("Not enough space");
		return -1;
	} else if (read > write && read + nbytes - fifosize < write) {
		memcpy(((fifo_table[i]).fifo).memoryZone + read, buff, fifosize - read);
		memcpy(((fifo_table[i]).fifo).memoryZone, buff + fifosize - read, read
				+ nbytes - fifosize);
		((fifo_table[i]).fifo).offSetToRead = write + nbytes - fifosize;
	} else if (read + nbytes < write) {
		memcpy(((fifo_table[i]).fifo).memoryZone + read, buff, nbytes);
		if (read + nbytes == fifosize) {
			((fifo_table[i]).fifo).offSetToRead = 0;
		} else {
			((fifo_table[i]).fifo).offSetToRead += nbytes;
		}
	}

	return nbytes;
}

/*
 * closeFifo
 * donde estaba el fifo_id ponerlo en -1
 * no se me ocurre como hacer el free de la zona de memoria
 * deberia leer el codigo del malloc xD para ver como hacer la inversa
 */

int close(int fd) {
	int i,j;
	for (i = 0; i < MAXFIFOSCANT; ++i) {
		if ((fifo_table[i]).fifo_id == fd) {
			for(j=0; j<50;j++){
			(fifo_table[i]).name[j] = '\0';
			}
			(fifo_table[i]).fifo_id = -1;
			//No se por que si descomento alguna(cualquiera) de las siguientes 2 lineas muere
			((fifo_table[i]).fifo).offSetToRead = 0;
			((fifo_table[i]).fifo).offSetToWrite = 0;
			break;
		}
	}
	return 0;
}

/* ==============
 */
/*
 int procesitoA(int argc, char **argv) {
 int fd;

 if ((fd = makeFifo("hola")) == -1){
 return -1;
 }
 char s[] = "hola mundo esto es para probar el fifo\n";
 writeFifo(fd,s,strlen(s));

 return 0;
 }
 int procesitoB(int argc, char **argv) {
 int fd;
 fd = openFifo("hola");
 char s[60];
 readFifo(fd,s,60);
 printf("Lei del fifo: %s",s);
 close(fd);
 return 0;
 }
 int main(int argc, char **argv) {

 initializeFifos();

 procesitoA(0,NULL);
 procesitoB(0,NULL);

 return 0;
 }*/
